// Copyright (c) 2010 SuccessFactors, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//     * Redistributions of source code must retain the above
//       copyright notice, this list of conditions and the following
//       disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials
//       provided with the distribution.
//
//     * Neither the name of the SuccessFactors, Inc. nor the names of
//       its contributors may be used to endorse or promote products
//       derived from this software without specific prior written
//       permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

package org.owasp.jxt.runtime;

import java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;

/**
 * JxtBodyContent (TODO: this class may not be needed since
 * PageContext seems to provide a default implementation of
 * BodyContext in order to implement pushBody()).
 *
 * @author Jeffrey Ichnowski
 * @version $Revision: 8 $
 */
public class JxtBodyContent extends BodyContent {

    static final int BUFFER_SIZE = 2048;

    private char[] _buffer;
    private int _offset;
    private String _lineSeparator;
    private boolean _closed;

    public JxtBodyContent(JspWriter out) {
        super(out);

        _offset = 0;
        _buffer = new char[BUFFER_SIZE];

        try {
            _lineSeparator = System.getProperty("line.separator");
        } catch (SecurityException ignore) {
            _lineSeparator = "\n";
        }
    }

    /** {@inheritDoc} */
    public final Reader getReader() {
        return new CharArrayReader(_buffer, 0, _offset);
    }

    /** {@inheritDoc} */
    public final void writeOut(final Writer writer) throws IOException {
        writer.write(_buffer, 0, _offset);
    }

    /** {@inheritDoc} */
    public final String getString() {
        return new String(_buffer, 0, _offset);
    }

    /** {@inheritDoc} */
    public final void write(final char[] data, int off, int len) throws IOException {
        if (_closed) {
            throw new IOException("already closed");
        }

        if (len > 0) {
            int targetLength = _offset + len;
            if (targetLength < _buffer.length) {
                int newLength = _buffer.length * 2;
                while (newLength < targetLength) {
                    newLength *= 2;
                }

                char[] tmp = new char[newLength];
                System.arraycopy(_buffer, 0, tmp, 0, _offset);
                _buffer = tmp;
            }

            System.arraycopy(data, off, _buffer, _offset, len);
            _offset += len;
        }
    }

    /** {@inheritDoc} */
    public final void println(final String str) throws IOException {
        print(str);
        println();
    }

    /** {@inheritDoc} */
    public final void println(final char[] data) throws IOException {
        print(data);
        println();
    }

    /** {@inheritDoc} */
    public final void println(final Object obj) throws IOException {
        print(obj);
        println();
    }

    /** {@inheritDoc} */
    public final void println(final long value) throws IOException {
        print(value);
        println();
    }

    /** {@inheritDoc} */
    public final void println(final double value) throws IOException {
        print(value);
        println();
    }

    /** {@inheritDoc} */
    public final void println(final float value) throws IOException {
        print(value);
        println();
    }

    /** {@inheritDoc} */
    public final void println(final int value) throws IOException {
        print(value);
        println();
    }

    /** {@inheritDoc} */
    public final void println(final char value) throws IOException {
        print(value);
        println();
    }

    /** {@inheritDoc} */
    public final void println(final boolean value) throws IOException {
        print(value);
        println();
    }

    /** {@inheritDoc} */
    public final void println() throws IOException {
        newLine();
    }

    /** {@inheritDoc} */
    public final void clear() throws IOException {
        _offset = 0;
    }

    /** {@inheritDoc} */
    public final void print(final String str) throws IOException {
        write(str == null ? "null" : str); // this is according to spec...
    }

    /** {@inheritDoc} */
    public final void print(final Object obj) throws IOException {
        write(String.valueOf(obj));
    }

    /** {@inheritDoc} */
    public final void print(final char[] value) throws IOException {
        write(value);
    }

    /** {@inheritDoc} */
    public final void print(final double value) throws IOException {
        write(String.valueOf(value));
    }

    /** {@inheritDoc} */
    public final void print(final float value) throws IOException {
        write(String.valueOf(value));
    }

    /** {@inheritDoc} */
    public final void print(final long value) throws IOException {
        write(String.valueOf(value));
    }

    /** {@inheritDoc} */
    public final void print(final int value) throws IOException {
        write(String.valueOf(value));
    }

    /** {@inheritDoc} */
    public final void print(final char value) throws IOException {
        write(String.valueOf(value));
    }

    /** {@inheritDoc} */
    public final void print(final boolean value) throws IOException {
        write(String.valueOf(value));
    }

    /** {@inheritDoc} */
    public final void newLine() throws IOException {
        write(_lineSeparator);
    }

    /** {@inheritDoc} */
    public final void close() throws IOException {
        _closed = true;
    }

    /** {@inheritDoc} */
    public final int getRemaining() {
        // this is not accurate.  More likely an OOME will be thrown
        // first, but we'll also get an NegativeArraySizeException as
        // soon as the buffer doubles to -2147483648 from 1073741824.
        return Integer.MAX_VALUE;
    }

    /** {@inheritDoc} */
    public final void clearBuffer() throws IOException {
        _offset = 0;
    }

} // JxtBodyContent
